Back to Home

1 Introduction

This project consists of a comprehensive comparison of execution time and Time use in Python, R for computational operations common in data science, namely generic loop and vectorized operations, matrix multiplication and inversion, and some popular computationally heavy statistical and ML algorithms.

1.1 Why R and Python

R and Python are arguably the two most popular open-source programming language used in data science. Both are considered high-level programming languages with many abstractions built to feature simple syntax.

Python is also widely outside for programming outside data science and ranks first in many popularity indices like the TIOBE index. Its popularity in data science can be explained by its extensive ecosystem of open-source libraries contributed by the programming community, such as NumPy, pandas, scikit-learn which provide flexible algorithms for data manipulation, analysis, and visualization. Python’s ecosystem has many libraries beyond data science, such as for we

b development and natural language processing. Python has extensive documentation on GitHub. Compared to R, it is more popular in the data science industry and in the academic machine learning community. Python libraries are typically built in C/C++ or Fortran for efficient implementations.

R is a programming language designed specifically for statistical computing and graphics. Like Python, R’s main strength is its extensive collection of open-source packages contributed by the community of users, which mainly consists of statisticians and researchers. It features built-in functions for popular statistical algorithms like linear regression as well as flexible graphical capabilities. There are also many packages for complex data manipulation like the Tidyverse collection which includes dplyr and the high-quality visualization tool ggplot2. R’s syntax is tailored for statistical analysis, using vectors as its data structure for storing and manipulating data. It includes many built-in reproducibility features like setting a seed for pseudo-random number generators. Its packages are also typically implemented in C or C++.

Other popular high-level programming languages in data science include Java and relative newcomer Julia, and common proprietary programming languages include SAS, Stata, and MATLAB.

1.2 Setup

For each algorithm, I measure execution time and Time use using the benchmark package in R and the time and profile libraries in Python. The algorithms were meant to be written in a way that is as structurally similar as possible in both languages, but the implementations of base functions vary greatly between the two languages. Ultimately, this is what makes the comparison interesting since there can be great differences in execution time for similar operations, but it also means that an algorithm can be poorly optimized in a language and artificially seem much faster in the other. For instance, people often criticize the speed of loops in R and my tests agree with this criticism, but these operations can almost always be made much faster by using vectorized operations.

I simulated give datasets in R typically from a standard Normal distribution, with sample sizes varying \(10^3\) to \(10^7\). I ran scripts in R and Python on these simulated datasets and their execution time and Time use were recorded in CSV files. I used R markdown to generate this webpage, using the plotly package to generate interactive plots. I also included theoretical Big-O complexity of the algorithms based on the most simple form of the algorithm.

All code for the scripts is available in the GitHub repository and all code use to generate my website using the theme … is available in the Github repository …

The following algorithms were tested: a simple loop and a vectorized implementation, matrix multiplication and inversion, linear regression, a bootstrap algorithm, and a SVM algorithm. When possible, I have implemented a simple version of these algorithms using only base functions in the language as well as a popular package/library. For instance, for linear regression I use the lm() function in R and the Scikit-Learn library in Python as well as an algorithm using only matrix multiplication and inversion. Of course, these two matrix operations are themselves algorithms with many different possible implementations that I do not know anything about and which are apparently active areas of research in computer science. I am somewhat biased since I mainly use R in my academic work and am more familiar with the most optimized packages in R rather than Python.

In short, this project contained three phases, which are very representative of a typical data science project: 1) Simulating data, 2) Writing and running various algorithms, and 3) Analyzing the data.

2 Comparison

2.1 Loop operations

2.1.1 Loop sums

Function loop_sum(n)
    Initialize sum to 0
    For i from 1 to n
        sum <- sum + i
    End For
    Return sum
End Function

The initialization step is O(1), a linear operation like a sum or a mean is also O(1), and by definition the loop is \(O(n)\) which is the overall complexity of the algorithm.

Here is the code in Python

and in R

I include below the code used to generate interactive plots of execution time and memory usage with the plotly library in R. Note that the plot is in the log scale.

library(plotly)
# Read data
R <- read.csv("/Users/ancavanciupopescu/Desktop/Classes/CS 32/Final project/Results/Results_R.csv")
python <- read.csv("/Users/ancavanciupopescu/Desktop/Classes/CS 32/Final project/Results/Results_python.csv")
merged_data <- merge(R, python, by=c("Algorithm", "n"), suffixes = c("R", "python"))
algorithm_names <- c('loop_sum','loop_geom_mean', 'vectorized_geom_mean', 'matrix_multiplication', 
                 'matrix_inversion', 'linear_regression_package', 'linear_regression_base', 
                 'bootstrap_package', 'bootstrap_base', 'svm_package', 'svm_base', 
                 'Metropolis_Hastings', 'MCMC_stan')

# Compute Big-O complexity
algos <- c("loop_sum") # We only plot one algorithm here but in other plots I have multiple algorithms
n_values <- seq(2, 6, by = 0.1)
O_n <- 10^n_values/10^4
O_n_python_1 <- O_n*python[python$Algorithm == algos[1],]$Time[3] # The pre-factors are calibrated on n=10^4
O_n_R_1 <- O_n*R[R$Algorithm == algos[1],]$Time[3]

# Time plot
plot_ly() %>%
  add_trace(data = R[R$Algorithm == algos[1],], x = ~log(n, 10), y = ~Time, 
            type = 'scatter', mode = 'lines+markers', name = 'R',
            line = list(color = "blue", dash = 'solid'),
            marker = list(color = "blue", symbol = 'circle')) %>%
  add_trace(data = python[python$Algorithm == algos[1],], x = ~log(n, 10), y = ~Time, 
            type = 'scatter', mode = 'lines+markers', name = 'loop_sum Python',
            line = list(color = "red", dash = 'solid'),
            marker = list(color = "red", symbol = 'dot')) %>%
  add_trace(x = n_values, y = O_n_python_1, type = 'scatter', mode = 'lines',
            name = 'O(n)', line = list(color = 'black', dash = 'dash')) %>%
  add_trace(x = n_values, y = O_n_R_1, type = 'scatter', mode = 'lines',
            name = 'O(n)', line = list(color = 'black', dash = 'dash'), showlegend = FALSE) %>%
  layout(title = "Execution Time",
         xaxis = list(title = "log(n)", tickmode = "array", tickvals = 0:6, ticktext = as.character(0:6)),
         yaxis = list(title = "Time (s)"),
         legend = list(title = "Legend", orientation = "h", x = 0.3, y = -0.2))

We see that loops in R run two to three times faster than in Pyton. We see that O(n) fits the data very well. Memory usage is not recorded in R, and it does not seem to scale considerably with \(n\) in Python. This is a win for R, but it is well-known that loops are slow in both R and Python due to the many abstractions made by the programming languages. It is often suggested to vectorize operations, which can speed up loops considerably.

2.1.2 Vectorized operations

Vectorized operations are still loops, but they are typically compiled directly in C or Fortran which is much faster than either R or Python. In addition, the operations are optimized for the CPU to perform multiple operations on the data. The computational complexity is theoretically still the same as a loop, but the pre-factor is reduced, and due to more efficient memory allocation it is possible for the order of execution time to be reduced as well. In the following plots, I compare the computation of the geometric mean computed as \(\exp(\frac{1}{n} \sum_{i=1}^n \log y_i)\) through a loop and with a vectorized operation.

We see that loops in Python and R are very slow compared to the vectorized operation.

algos <- c("vectorized_geom_mean")
n_values <- seq(2, 6, by = 0.1)
O_n <- 10^n_values/10^4
O_n_python_1 <- O_n*python[python$Algorithm == algos[1],]$Time[3]
O_n_R_1 <- O_n*R[R$Algorithm == algos[1],]$Time[3]
plot_ly() %>%
  add_trace(data = R[R$Algorithm == algos[1],], x = ~log(n, 10), y = ~Time, 
            type = 'scatter', mode = 'lines+markers', name = 'loop_geom_mean R',
            line = list(color = "blue", dash = 'solid'),
            marker = list(color = "blue", symbol = 'circle')) %>%
  add_trace(data = python[python$Algorithm == algos[1],], x = ~log(n, 10), y = ~Time, 
            type = 'scatter', mode = 'lines+markers', name = 'loop_geom_mean Python',
            line = list(color = "red", dash = 'solid'),
            marker = list(color = "red", symbol = 'dot')) %>%
  add_trace(x = n_values, y = O_n_R_1, type = 'scatter', mode = 'lines',
            name = 'O(n)', line = list(color = 'black', dash = 'dash')) %>%
  layout(title = "Execution Time",
         xaxis = list(title = "log(n)", tickmode = "array", tickvals = 0:6, ticktext = as.character(0:6)),
         yaxis = list(title = "Time (s)"),
         legend = list(title = "Legend", orientation = "h", x = 0.3, y = -0.2))

2.2 Matrix operations

2.2.1 Matrix multiplication and inversion

For each pair of row from \(A\) and column from \(B\), \(n\) multiplications are performed. For each of the \(n\) multiplications, there is an addition. This gives computational complexity \(\mathcal{O}(n^3)\). Now, Python and R likely have a more efficient version through some smart algorithm. Likewise, finding the inverse through Gaussian elimination is \(\mathcal{O}(n^3)\). However, the implementations in R and Python seem to scale linearly or even better with \(n\). An important note is that memory also seems to increase linearly which may explain why the time is much better than the theoretical complexity.

Either \(\mathcal{O}(n d^2)\) or \(\mathcal{O}(d^3)\).

2.3 Linear regression

Recall the OLS \(\beta = (X^T X)^{-1} X^T y\)

Function linear_regression(X, y)
    n <- number of rows in X
    p <- number of columns in X
    
    // Augment X with a column 1 to include an intercept
    X_b <- concatenate([ones(n, 1), X], axis=1)
    
    // Compute the coefficients
    beta_hat <- inverse(X_b.T @ X_b) @ (X_b.T @ y) 
    
    Return beta_hat
End Function

The matrix augmentation operation is \(O(n)\) since we are appending \(n\) rows. The matrix multiplication and inversion are the dominating steps of this algorithm. As explained in the previous section on matrices, the matrix multiplication X_b.T @ X_b step is \(O(n \times (p+1)^2)\) while the matrix inversion is \(O((p+1)^3)\), although these matrix operations are likely implemented more efficiently in Python and R. The last step of multiplying the matrix inverse(X_b.T @ X_b) with the vector (X_b.T @ y) is \(O((p+1)^2)\). Therefore, the overall complexity is \(O(p^3)\) or \(O(n \times (p+1)^2)\) depending on whether \(p<<n\). In this case, since we keep \(p=10\) and we increase \(n\) to \(n=10^6\), the dominating step is \(O(n)\).

2.4 Bootstrap

I expected computational complexity \(\mathcal{O}(n \log (n))\), but Python blows up.

Function bootstrap(data, statistic, B, alpha)
    n <- length of data
    idx <- generate B sets of indices, each with n random integers between 0 and n-1
    samples <- extract data elements based on idx
    stat <- sort(statistic(samples))
    lower_CI <- compute (100*(1-alpha)/2)th sample quantile
    upper_CI <- compute (100*(1-(1-alpha)/2)th sample quantile
    Return lower_CI, upper_CI
End Function

The idx resampling step is \(O(n \times B)\) and extracting the samples is also \(O(n \times B)\). For a linear statistic like a sample mean, the statistic step is also \(O(n \times B)\). The sorting step depends on the algorithm used, but the one used in Python is Timsort which has \(O(B \log (B))\). After that, computing the two sample quantiles on the sorted data is \(O(1)\). However, a potentially more efficient way of doing this step is using sample quantiles since we are only interested in two sample quantiles which may avoid sorting the entire dataset. Therefore, since we increase \(B\) and keep \(n=10^3\) fixed, the dominating step is the resampling/extracting/statistic step, which has complexity \(O(n \times B)\).

2.5 Markov chain Monte Carlo

I expect the computational complexity to be \(\mathcal{O}(n)\).

Function metropolis_hastings(X, y, B, beta_0, proposal_sd, sigma)
    // Augment X with a column 1 to include an intercept
    X_b <- concatenate column of ones to X
    
    // Initialize parameters
    current_beta <- beta_0
    samples <- current_beta
    
    // Compute initial values for likelihood and prior
    Xb <- X_b dot current_beta
    current_likelihood <- sum(log(N(y|Xb,sigma))
    current_prior <- sum(log(N(current_beta|mu0,sigma0)))
    
    // Sampling
    For i from 1 to B
        proposed_beta <- sample N(current_beta,proposal_sd)
        Xb_proposed <- X_b dot proposed_beta
        proposed_likelihood <- sum(log(N(y|Xb_proposed,sigma))
        proposed_prior <- sum(log(N(proposed_beta|mu0,sigma0)))
        
        // Compute acceptance probability
        p_accept <- exp(proposed_likelihood + proposed_prior - current_likelihood - current_prior)
        
        // Accept/reject new beta
        U <- sample Unif(0,1)
        If U < p_accept
            current_beta <- proposed_beta
            current_likelihood <- proposed_likelihood
            current_prior <- proposed_prior
        
        Append current_beta to samples
    
    Return samples
End Function

Augmenting the matrix is \(O(n)\), the matrix dot products from linear regression is \(O(np)\), computing the log-likelihood is \(O(n)\) and computing the prior is \(O(p)\). Therefore, running the loop for B iterations has complexity \(O(n \times p \times B)\).

2.6 Support vector machine

I won’t say much about this because I don’t know machine learning but my understanding of the algorithm using a simplified form of gradient descent is as follows.

Function svm(X, y, epochs, learning_rate, C)
    // Initialize parameters
    Initialize weight vector w to 0
    Initialize bias b to 0
    
    For each epoch from 1 to epochs
        For each sample i from 1 to length of y
            Compute decision_value = X[i] dot (w + b)
            
            // Check if data is on the correct side of the margin
            If y[i] * decision_value < 1 then
                // Update w and b for incorrectly classified samples
                Update w = w + learning_rate * (y[i] * X[i] - 2 * (1/C) * w)
                Update b = b + learning_rate * y[i]
            Else
                // Apply only the regularization update if sample is classified correctly
                Update w = w - learning_rate * (2 * (1/C) * w)
            
    Return w, b
End Function

The initializations are \(O(p)\) and \(O(1)\), the outer loop runs for epochs iterations and the inner loop runs for \(n\) interations, the product X[i] dot C is \(O(p)\), so the overall complexity is \(O(\text{epochs} \times n \times p)\).

9 min 126min

and

3 Discussion

3.0.0.1 Loops

“For-loops are not idiomatic R code” is something I have heard many times. In trivial cases or fast prototyping, for-loops are fantastic yet I have always converted them into base::apply functions, or pbapply::pbapply for progress bars or even parallel::parApply for parallel computation afterwards.

3.0.0.2 Speed depending on the machine

3.0.0.3 Processor time vs. clock time

Ultimately, I care more about clock time but maybe for production code it is total processing time from parellel servers that counts.

3.0.0.4 What does Time usage really mean and how can we measure it?

3.0.0.5 Estimating uncertainty within and across datasets and across methods

3.0.0.6 Other considerations than speed and Time

3.0.0.7 My experience using both Python and R

It was difficult to simulate the data and store in a manner that can be easily read in both Python and R. If I was just using R I would use a .rds file with an absurd object containing all the data in one object easily imported, but to be read in Python I had to save the data in several .csv files which were read with an awkward structure in Python including an infamous errors=‘coerce’ line. I don’t really understand what it does but it solved the problem that my file included both strings and numerics, though I only care about analyzing the numerics. This is my own fault because I don’t know Python well, but R makes it (dangerously) easy to use different objects without thinking about structure too much. For the purpose of this project, I didn’t really care much about importing the data smoothly as long as it got done since I was focused on making the algorithms comparable. An interesting aspect that I didn’t test was the speed of reading data, which I clearly don’t know enough about to test fairly, but it can be a major consideration for large datasets which can need clusters of CPUs to load.

3.0.0.8 My experience using interactive visualization and a website

Plotting is much easier and better supported in ggplot, but I used plotly to make these interactive plots. I don’t really like them for conveying information, as I think they ultimately distract the reader from the information, but it attracts attention and is interesting for a blog post format like this. I could not imagine using them in a paper.

3.0.0.9 Usage in industry and academia

3.0.0.10 Probabilistic programing and bayesian statistcs

Comparing MCMC samplers: https://statmodeling.stat.columbia.edu/2024/04/27/evaluating-mcmc-samplers/

4 References

LS0tCnRpdGxlOiAiQ29tcHV0YXRpb25hbCBwZXJmb3JtYW5jZSBvZiBSIGFuZCBQeXRob24gZm9yIGRhdGEgc2NpZW5jZSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0aGVtZTogbHVtZW4KLS0tCjxhIGhyZWY9J2h0dHBzOi8vbGVvdmFuY2l1LmdpdGh1Yi5pby8nIGNsYXNzPSdidG4gYnRuLXByaW1hcnknPkJhY2sgdG8gSG9tZTwvYT4KCiMgSW50cm9kdWN0aW9uCgpUaGlzIHByb2plY3QgY29uc2lzdHMgb2YgYSBjb21wcmVoZW5zaXZlIGNvbXBhcmlzb24gb2YgZXhlY3V0aW9uIHRpbWUgYW5kIFRpbWUgdXNlIGluIFB5dGhvbiwgUiBmb3IgY29tcHV0YXRpb25hbCBvcGVyYXRpb25zIGNvbW1vbiBpbiBkYXRhIHNjaWVuY2UsIG5hbWVseSBnZW5lcmljIGxvb3AgYW5kIHZlY3Rvcml6ZWQgb3BlcmF0aW9ucywgbWF0cml4IG11bHRpcGxpY2F0aW9uIGFuZCBpbnZlcnNpb24sIGFuZCBzb21lIHBvcHVsYXIgY29tcHV0YXRpb25hbGx5IGhlYXZ5IHN0YXRpc3RpY2FsIGFuZCBNTCBhbGdvcml0aG1zLgoKCiMjIFdoeSBSIGFuZCBQeXRob24KClIgYW5kIFB5dGhvbiBhcmUgYXJndWFibHkgdGhlIHR3byBtb3N0IHBvcHVsYXIgb3Blbi1zb3VyY2UgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgdXNlZCBpbiBkYXRhIHNjaWVuY2UuIEJvdGggYXJlIGNvbnNpZGVyZWQgaGlnaC1sZXZlbCBwcm9ncmFtbWluZyBsYW5ndWFnZXMgd2l0aCBtYW55IGFic3RyYWN0aW9ucyBidWlsdCB0byBmZWF0dXJlIHNpbXBsZSBzeW50YXguCgpQeXRob24gaXMgYWxzbyB3aWRlbHkgb3V0c2lkZSBmb3IgcHJvZ3JhbW1pbmcgb3V0c2lkZSBkYXRhIHNjaWVuY2UgYW5kIHJhbmtzIGZpcnN0IGluIG1hbnkgcG9wdWxhcml0eSBpbmRpY2VzIGxpa2UgdGhlIFRJT0JFIGluZGV4LiBJdHMgcG9wdWxhcml0eSBpbiBkYXRhIHNjaWVuY2UgY2FuIGJlIGV4cGxhaW5lZCBieSBpdHMgZXh0ZW5zaXZlIGVjb3N5c3RlbSBvZiBvcGVuLXNvdXJjZSBsaWJyYXJpZXMgY29udHJpYnV0ZWQgYnkgdGhlIHByb2dyYW1taW5nIGNvbW11bml0eSwgc3VjaCBhcyBOdW1QeSwgcGFuZGFzLCBzY2lraXQtbGVhcm4gd2hpY2ggcHJvdmlkZSBmbGV4aWJsZSBhbGdvcml0aG1zIGZvciBkYXRhIG1hbmlwdWxhdGlvbiwgYW5hbHlzaXMsIGFuZCB2aXN1YWxpemF0aW9uLiBQeXRob24ncyBlY29zeXN0ZW0gaGFzIG1hbnkgbGlicmFyaWVzIGJleW9uZCBkYXRhIHNjaWVuY2UsIHN1Y2ggYXMgZm9yIHdlCgpiIGRldmVsb3BtZW50IGFuZCBuYXR1cmFsIGxhbmd1YWdlIHByb2Nlc3NpbmcuIFB5dGhvbiBoYXMgZXh0ZW5zaXZlIGRvY3VtZW50YXRpb24gb24gR2l0SHViLiBDb21wYXJlZCB0byBSLCBpdCBpcyBtb3JlIHBvcHVsYXIgaW4gdGhlIGRhdGEgc2NpZW5jZSBpbmR1c3RyeSBhbmQgaW4gdGhlIGFjYWRlbWljIG1hY2hpbmUgbGVhcm5pbmcgY29tbXVuaXR5LiBQeXRob24gbGlicmFyaWVzIGFyZSB0eXBpY2FsbHkgYnVpbHQgaW4gQy9DKysgb3IgRm9ydHJhbiBmb3IgZWZmaWNpZW50IGltcGxlbWVudGF0aW9ucy4KClIgaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSBkZXNpZ25lZCBzcGVjaWZpY2FsbHkgZm9yIHN0YXRpc3RpY2FsIGNvbXB1dGluZyBhbmQgZ3JhcGhpY3MuIExpa2UgUHl0aG9uLCBSJ3MgbWFpbiBzdHJlbmd0aCBpcyBpdHMgZXh0ZW5zaXZlIGNvbGxlY3Rpb24gb2Ygb3Blbi1zb3VyY2UgcGFja2FnZXMgY29udHJpYnV0ZWQgYnkgdGhlIGNvbW11bml0eSBvZiB1c2Vycywgd2hpY2ggbWFpbmx5IGNvbnNpc3RzIG9mIHN0YXRpc3RpY2lhbnMgYW5kIHJlc2VhcmNoZXJzLiBJdCBmZWF0dXJlcyBidWlsdC1pbiBmdW5jdGlvbnMgZm9yIHBvcHVsYXIgc3RhdGlzdGljYWwgYWxnb3JpdGhtcyBsaWtlIGxpbmVhciByZWdyZXNzaW9uIGFzIHdlbGwgYXMgZmxleGlibGUgZ3JhcGhpY2FsIGNhcGFiaWxpdGllcy4gVGhlcmUgYXJlIGFsc28gbWFueSBwYWNrYWdlcyBmb3IgY29tcGxleCBkYXRhIG1hbmlwdWxhdGlvbiBsaWtlIHRoZSBUaWR5dmVyc2UgY29sbGVjdGlvbiB3aGljaCBpbmNsdWRlcyBkcGx5ciBhbmQgdGhlIGhpZ2gtcXVhbGl0eSB2aXN1YWxpemF0aW9uIHRvb2wgZ2dwbG90Mi4gUidzIHN5bnRheCBpcyB0YWlsb3JlZCBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMsIHVzaW5nIHZlY3RvcnMgYXMgaXRzIGRhdGEgc3RydWN0dXJlIGZvciBzdG9yaW5nIGFuZCBtYW5pcHVsYXRpbmcgZGF0YS4gSXQgaW5jbHVkZXMgbWFueSBidWlsdC1pbiByZXByb2R1Y2liaWxpdHkgZmVhdHVyZXMgbGlrZSBzZXR0aW5nIGEgc2VlZCBmb3IgcHNldWRvLXJhbmRvbSBudW1iZXIgZ2VuZXJhdG9ycy4gSXRzIHBhY2thZ2VzIGFyZSBhbHNvIHR5cGljYWxseSBpbXBsZW1lbnRlZCBpbiBDIG9yIEMrKy4KCgpPdGhlciBwb3B1bGFyIGhpZ2gtbGV2ZWwgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGluIGRhdGEgc2NpZW5jZSBpbmNsdWRlIEphdmEgYW5kIHJlbGF0aXZlIG5ld2NvbWVyIEp1bGlhLCBhbmQgY29tbW9uIHByb3ByaWV0YXJ5IHByb2dyYW1taW5nIGxhbmd1YWdlcyBpbmNsdWRlIFNBUywgU3RhdGEsIGFuZCBNQVRMQUIuCgojIyBTZXR1cAoKRm9yIGVhY2ggYWxnb3JpdGhtLCBJIG1lYXN1cmUgZXhlY3V0aW9uIHRpbWUgYW5kIFRpbWUgdXNlIHVzaW5nIHRoZSBiZW5jaG1hcmsgcGFja2FnZSBpbiBSIGFuZCB0aGUgdGltZSBhbmQgcHJvZmlsZSBsaWJyYXJpZXMgaW4gUHl0aG9uLiBUaGUgYWxnb3JpdGhtcyB3ZXJlIG1lYW50IHRvIGJlIHdyaXR0ZW4gaW4gYSB3YXkgdGhhdCBpcyBhcyBzdHJ1Y3R1cmFsbHkgc2ltaWxhciBhcyBwb3NzaWJsZSBpbiBib3RoIGxhbmd1YWdlcywgYnV0IHRoZSBpbXBsZW1lbnRhdGlvbnMgb2YgYmFzZSBmdW5jdGlvbnMgdmFyeSBncmVhdGx5IGJldHdlZW4gdGhlIHR3byBsYW5ndWFnZXMuIFVsdGltYXRlbHksIHRoaXMgaXMgd2hhdCBtYWtlcyB0aGUgY29tcGFyaXNvbiBpbnRlcmVzdGluZyBzaW5jZSB0aGVyZSBjYW4gYmUgZ3JlYXQgZGlmZmVyZW5jZXMgaW4gZXhlY3V0aW9uIHRpbWUgZm9yIHNpbWlsYXIgb3BlcmF0aW9ucywgYnV0IGl0IGFsc28gbWVhbnMgdGhhdCBhbiBhbGdvcml0aG0gY2FuIGJlIHBvb3JseSBvcHRpbWl6ZWQgaW4gYSBsYW5ndWFnZSBhbmQgYXJ0aWZpY2lhbGx5IHNlZW0gbXVjaCBmYXN0ZXIgaW4gdGhlIG90aGVyLiBGb3IgaW5zdGFuY2UsIHBlb3BsZSBvZnRlbiBjcml0aWNpemUgdGhlIHNwZWVkIG9mIGxvb3BzIGluIFIgYW5kIG15IHRlc3RzIGFncmVlIHdpdGggdGhpcyBjcml0aWNpc20sIGJ1dCB0aGVzZSBvcGVyYXRpb25zIGNhbiBhbG1vc3QgYWx3YXlzIGJlIG1hZGUgbXVjaCBmYXN0ZXIgYnkgdXNpbmcgdmVjdG9yaXplZCBvcGVyYXRpb25zLgoKSSBzaW11bGF0ZWQgZ2l2ZSBkYXRhc2V0cyBpbiBSIHR5cGljYWxseSBmcm9tIGEgc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgd2l0aCBzYW1wbGUgc2l6ZXMgdmFyeWluZyAkMTBeMyQgdG8gJDEwXjckLiBJIHJhbiBzY3JpcHRzIGluIFIgYW5kIFB5dGhvbiBvbiB0aGVzZSBzaW11bGF0ZWQgZGF0YXNldHMgYW5kIHRoZWlyIGV4ZWN1dGlvbiB0aW1lIGFuZCBUaW1lIHVzZSB3ZXJlIHJlY29yZGVkIGluIENTViBmaWxlcy4gSSB1c2VkIFIgbWFya2Rvd24gdG8gZ2VuZXJhdGUgdGhpcyB3ZWJwYWdlLCB1c2luZyB0aGUgcGxvdGx5IHBhY2thZ2UgdG8gZ2VuZXJhdGUgaW50ZXJhY3RpdmUgcGxvdHMuIEkgYWxzbyBpbmNsdWRlZCB0aGVvcmV0aWNhbCBCaWctTyBjb21wbGV4aXR5IG9mIHRoZSBhbGdvcml0aG1zIGJhc2VkIG9uIHRoZSBtb3N0IHNpbXBsZSBmb3JtIG9mIHRoZSBhbGdvcml0aG0uCgpBbGwgY29kZSBmb3IgdGhlIHNjcmlwdHMgaXMgYXZhaWxhYmxlIGluIHRoZSBHaXRIdWIgcmVwb3NpdG9yeSBhbmQgYWxsIGNvZGUgdXNlIHRvIGdlbmVyYXRlIG15IHdlYnNpdGUgdXNpbmcgdGhlIHRoZW1lIC4uLiBpcyBhdmFpbGFibGUgaW4gdGhlIEdpdGh1YiByZXBvc2l0b3J5IC4uLgoKVGhlIGZvbGxvd2luZyBhbGdvcml0aG1zIHdlcmUgdGVzdGVkOiBhIHNpbXBsZSBsb29wIGFuZCBhIHZlY3Rvcml6ZWQgaW1wbGVtZW50YXRpb24sIG1hdHJpeCBtdWx0aXBsaWNhdGlvbiBhbmQgaW52ZXJzaW9uLCBsaW5lYXIgcmVncmVzc2lvbiwgYSBib290c3RyYXAgYWxnb3JpdGhtLCBhbmQgYSBTVk0gYWxnb3JpdGhtLiBXaGVuIHBvc3NpYmxlLCBJIGhhdmUgaW1wbGVtZW50ZWQgYSBzaW1wbGUgdmVyc2lvbiBvZiB0aGVzZSBhbGdvcml0aG1zIHVzaW5nIG9ubHkgYmFzZSBmdW5jdGlvbnMgaW4gdGhlIGxhbmd1YWdlIGFzIHdlbGwgYXMgYSBwb3B1bGFyIHBhY2thZ2UvbGlicmFyeS4gRm9yIGluc3RhbmNlLCBmb3IgbGluZWFyIHJlZ3Jlc3Npb24gSSB1c2UgdGhlIGxtKCkgZnVuY3Rpb24gaW4gUiBhbmQgdGhlIFNjaWtpdC1MZWFybiBsaWJyYXJ5IGluIFB5dGhvbiBhcyB3ZWxsIGFzIGFuIGFsZ29yaXRobSB1c2luZyBvbmx5IG1hdHJpeCBtdWx0aXBsaWNhdGlvbiBhbmQgaW52ZXJzaW9uLiBPZiBjb3Vyc2UsIHRoZXNlIHR3byBtYXRyaXggb3BlcmF0aW9ucyBhcmUgdGhlbXNlbHZlcyBhbGdvcml0aG1zIHdpdGggbWFueSBkaWZmZXJlbnQgcG9zc2libGUgaW1wbGVtZW50YXRpb25zIHRoYXQgSSBkbyBub3Qga25vdyBhbnl0aGluZyBhYm91dCBhbmQgd2hpY2ggYXJlIGFwcGFyZW50bHkgYWN0aXZlIGFyZWFzIG9mIHJlc2VhcmNoIGluIGNvbXB1dGVyIHNjaWVuY2UuIEkgYW0gc29tZXdoYXQgYmlhc2VkIHNpbmNlIEkgbWFpbmx5IHVzZSBSIGluIG15IGFjYWRlbWljIHdvcmsgYW5kIGFtIG1vcmUgZmFtaWxpYXIgd2l0aCB0aGUgbW9zdCBvcHRpbWl6ZWQgcGFja2FnZXMgaW4gUiByYXRoZXIgdGhhbiBQeXRob24uCgpJbiBzaG9ydCwgdGhpcyBwcm9qZWN0IGNvbnRhaW5lZCB0aHJlZSBwaGFzZXMsIHdoaWNoIGFyZSB2ZXJ5IHJlcHJlc2VudGF0aXZlIG9mIGEgdHlwaWNhbCBkYXRhIHNjaWVuY2UgcHJvamVjdDogMSkgU2ltdWxhdGluZyBkYXRhLCAyKSBXcml0aW5nIGFuZCBydW5uaW5nIHZhcmlvdXMgYWxnb3JpdGhtcywgYW5kIDMpIEFuYWx5emluZyB0aGUgZGF0YS4KCgoKIyBDb21wYXJpc29uCgojIyBMb29wIG9wZXJhdGlvbnMKCiMjIyBMb29wIHN1bXMKCmBgYHBsYWludGV4dApGdW5jdGlvbiBsb29wX3N1bShuKQogICAgSW5pdGlhbGl6ZSBzdW0gdG8gMAogICAgRm9yIGkgZnJvbSAxIHRvIG4KICAgICAgICBzdW0gPC0gc3VtICsgaQogICAgRW5kIEZvcgogICAgUmV0dXJuIHN1bQpFbmQgRnVuY3Rpb24KYGBgCgpUaGUgaW5pdGlhbGl6YXRpb24gc3RlcCBpcyBPKDEpLCBhIGxpbmVhciBvcGVyYXRpb24gbGlrZSBhIHN1bSBvciBhIG1lYW4gaXMgYWxzbyBPKDEpLCBhbmQgYnkgZGVmaW5pdGlvbiB0aGUgbG9vcCBpcyAkTyhuKSQgd2hpY2ggaXMgdGhlIG92ZXJhbGwgY29tcGxleGl0eSBvZiB0aGUgYWxnb3JpdGhtLiAKCkhlcmUgaXMgdGhlIGNvZGUgaW4gUHl0aG9uCgoKYW5kIGluIFIKCgoKSSBpbmNsdWRlIGJlbG93IHRoZSBjb2RlIHVzZWQgdG8gZ2VuZXJhdGUgaW50ZXJhY3RpdmUgcGxvdHMgb2YgZXhlY3V0aW9uIHRpbWUgYW5kIG1lbW9yeSB1c2FnZSB3aXRoIHRoZSBwbG90bHkgbGlicmFyeSBpbiBSLiBOb3RlIHRoYXQgdGhlIHBsb3QgaXMgaW4gdGhlIGxvZyBzY2FsZS4KCgpgYGB7cixtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHBsb3RseSkKIyBSZWFkIGRhdGEKUiA8LSByZWFkLmNzdigiL1VzZXJzL2FuY2F2YW5jaXVwb3Blc2N1L0Rlc2t0b3AvQ2xhc3Nlcy9DUyAzMi9GaW5hbCBwcm9qZWN0L1Jlc3VsdHMvUmVzdWx0c19SLmNzdiIpCnB5dGhvbiA8LSByZWFkLmNzdigiL1VzZXJzL2FuY2F2YW5jaXVwb3Blc2N1L0Rlc2t0b3AvQ2xhc3Nlcy9DUyAzMi9GaW5hbCBwcm9qZWN0L1Jlc3VsdHMvUmVzdWx0c19weXRob24uY3N2IikKbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoUiwgcHl0aG9uLCBieT1jKCJBbGdvcml0aG0iLCAibiIpLCBzdWZmaXhlcyA9IGMoIlIiLCAicHl0aG9uIikpCmFsZ29yaXRobV9uYW1lcyA8LSBjKCdsb29wX3N1bScsJ2xvb3BfZ2VvbV9tZWFuJywgJ3ZlY3Rvcml6ZWRfZ2VvbV9tZWFuJywgJ21hdHJpeF9tdWx0aXBsaWNhdGlvbicsIAogICAgICAgICAgICAgICAgICdtYXRyaXhfaW52ZXJzaW9uJywgJ2xpbmVhcl9yZWdyZXNzaW9uX3BhY2thZ2UnLCAnbGluZWFyX3JlZ3Jlc3Npb25fYmFzZScsIAogICAgICAgICAgICAgICAgICdib290c3RyYXBfcGFja2FnZScsICdib290c3RyYXBfYmFzZScsICdzdm1fcGFja2FnZScsICdzdm1fYmFzZScsIAogICAgICAgICAgICAgICAgICdNZXRyb3BvbGlzX0hhc3RpbmdzJywgJ01DTUNfc3RhbicpCgojIENvbXB1dGUgQmlnLU8gY29tcGxleGl0eQphbGdvcyA8LSBjKCJsb29wX3N1bSIpICMgV2Ugb25seSBwbG90IG9uZSBhbGdvcml0aG0gaGVyZSBidXQgaW4gb3RoZXIgcGxvdHMgSSBoYXZlIG11bHRpcGxlIGFsZ29yaXRobXMKbl92YWx1ZXMgPC0gc2VxKDIsIDYsIGJ5ID0gMC4xKQpPX24gPC0gMTBebl92YWx1ZXMvMTBeNApPX25fcHl0aG9uXzEgPC0gT19uKnB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0kVGltZVszXSAjIFRoZSBwcmUtZmFjdG9ycyBhcmUgY2FsaWJyYXRlZCBvbiBuPTEwXjQKT19uX1JfMSA8LSBPX24qUltSJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdJFRpbWVbM10KCiMgVGltZSBwbG90CnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ1InLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnY2lyY2xlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xvb3Bfc3VtIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnZG90JykpICU+JQogIGFkZF90cmFjZSh4ID0gbl92YWx1ZXMsIHkgPSBPX25fcHl0aG9uXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICBuYW1lID0gJ08obiknLCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIGRhc2ggPSAnZGFzaCcpKSAlPiUKICBhZGRfdHJhY2UoeCA9IG5fdmFsdWVzLCB5ID0gT19uX1JfMSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsCiAgICAgICAgICAgIG5hbWUgPSAnTyhuKScsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsYWNrJywgZGFzaCA9ICdkYXNoJyksIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkV4ZWN1dGlvbiBUaW1lIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gImxvZyhuKSIsIHRpY2ttb2RlID0gImFycmF5IiwgdGlja3ZhbHMgPSAwOjYsIHRpY2t0ZXh0ID0gYXMuY2hhcmFjdGVyKDA6NikpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAocykiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpgYGAKCgpgYGB7ciBlY2hvPUZBTFNFfQojIE1lbW9yeSBwbG90CnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbG9vcF9zdW0gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdsb29wX3N1bSBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ2RvdCcpKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiTWVtb3J5IFVzYWdlIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gImxvZyhuKSIsIHRpY2ttb2RlID0gImFycmF5IiwgdGlja3ZhbHMgPSAwOjYsIHRpY2t0ZXh0ID0gYXMuY2hhcmFjdGVyKDA6NikpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTWVtb3J5IChNaUIpIiksCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QodGl0bGUgPSAiTGVnZW5kIiwgb3JpZW50YXRpb24gPSAiaCIsIHggPSAwLjMsIHkgPSAtMC4yKSkKYGBgCgoKV2Ugc2VlIHRoYXQgbG9vcHMgaW4gUiBydW4gdHdvIHRvIHRocmVlIHRpbWVzIGZhc3RlciB0aGFuIGluIFB5dG9uLiBXZSBzZWUgdGhhdCBPKG4pIGZpdHMgdGhlIGRhdGEgdmVyeSB3ZWxsLiBNZW1vcnkgdXNhZ2UgaXMgbm90IHJlY29yZGVkIGluIFIsIGFuZCBpdCBkb2VzIG5vdCBzZWVtIHRvIHNjYWxlIGNvbnNpZGVyYWJseSB3aXRoICRuJCBpbiBQeXRob24uIFRoaXMgaXMgYSB3aW4gZm9yIFIsIGJ1dCBpdCBpcyB3ZWxsLWtub3duIHRoYXQgbG9vcHMgYXJlIHNsb3cgaW4gYm90aCBSIGFuZCBQeXRob24gZHVlIHRvIHRoZSBtYW55IGFic3RyYWN0aW9ucyBtYWRlIGJ5IHRoZSBwcm9ncmFtbWluZyBsYW5ndWFnZXMuIEl0IGlzIG9mdGVuIHN1Z2dlc3RlZCB0byB2ZWN0b3JpemUgb3BlcmF0aW9ucywgd2hpY2ggY2FuIHNwZWVkIHVwIGxvb3BzIGNvbnNpZGVyYWJseS4KCiMjIyBWZWN0b3JpemVkIG9wZXJhdGlvbnMKCgpWZWN0b3JpemVkIG9wZXJhdGlvbnMgYXJlIHN0aWxsIGxvb3BzLCBidXQgdGhleSBhcmUgdHlwaWNhbGx5IGNvbXBpbGVkIGRpcmVjdGx5IGluIEMgb3IgRm9ydHJhbiB3aGljaCBpcyBtdWNoIGZhc3RlciB0aGFuIGVpdGhlciBSIG9yIFB5dGhvbi4gSW4gYWRkaXRpb24sIHRoZSBvcGVyYXRpb25zIGFyZSBvcHRpbWl6ZWQgZm9yIHRoZSBDUFUgdG8gcGVyZm9ybSBtdWx0aXBsZSBvcGVyYXRpb25zIG9uIHRoZSBkYXRhLiBUaGUgY29tcHV0YXRpb25hbCBjb21wbGV4aXR5IGlzIHRoZW9yZXRpY2FsbHkgc3RpbGwgdGhlIHNhbWUgYXMgYSBsb29wLCBidXQgdGhlIHByZS1mYWN0b3IgaXMgcmVkdWNlZCwgYW5kIGR1ZSB0byBtb3JlIGVmZmljaWVudCBtZW1vcnkgYWxsb2NhdGlvbiBpdCBpcyBwb3NzaWJsZSBmb3IgdGhlIG9yZGVyIG9mIGV4ZWN1dGlvbiB0aW1lIHRvIGJlIHJlZHVjZWQgYXMgd2VsbC4gSW4gdGhlIGZvbGxvd2luZyBwbG90cywgSSBjb21wYXJlIHRoZSBjb21wdXRhdGlvbiBvZiB0aGUgZ2VvbWV0cmljIG1lYW4gY29tcHV0ZWQgYXMgJFxleHAoXGZyYWN7MX17bn0gXHN1bV97aT0xfV5uIFxsb2cgeV9pKSQgdGhyb3VnaCBhIGxvb3AgYW5kIHdpdGggYSB2ZWN0b3JpemVkIG9wZXJhdGlvbi4KCgpgYGB7ciBlY2hvPUZBTFNFfQphbGdvcyA8LSBjKCJsb29wX2dlb21fbWVhbiIsICJ2ZWN0b3JpemVkX2dlb21fbWVhbiIpCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xvb3BfZ2VvbV9tZWFuIFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnY2lyY2xlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gUltSJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAndmVjdG9yaXplZF9nZW9tX21lYW4gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdsb29wX2dlb21fbWVhbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ2RvdCcpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICd2ZWN0b3JpemVkX2dlb21fbWVhbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGxheW91dCh0aXRsZSA9ICJFeGVjdXRpb24gVGltZSIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJsb2cobikiLCB0aWNrbW9kZSA9ICJhcnJheSIsIHRpY2t2YWxzID0gMDo2LCB0aWNrdGV4dCA9IGFzLmNoYXJhY3RlcigwOjYpKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKHMpIiksCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QodGl0bGUgPSAiTGVnZW5kIiwgb3JpZW50YXRpb24gPSAiaCIsIHggPSAwLjMsIHkgPSAtMC4yKSkKCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbG9vcF9nZW9tX21lYW4gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ3ZlY3Rvcml6ZWRfZ2VvbV9tZWFuIFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdkYXNoZG90JyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdsb29wX2dlb21fbWVhbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ2RvdCcpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ3ZlY3Rvcml6ZWRfZ2VvbV9tZWFuIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIk1lbW9yeSB1c2FnZSIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJsb2cobikiLCB0aWNrbW9kZSA9ICJhcnJheSIsIHRpY2t2YWxzID0gMDo2LCB0aWNrdGV4dCA9IGFzLmNoYXJhY3RlcigwOjYpKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIk1lbW9yeSAoTWlCKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCmBgYAoKV2Ugc2VlIHRoYXQgbG9vcHMgaW4gUHl0aG9uIGFuZCBSIGFyZSB2ZXJ5IHNsb3cgY29tcGFyZWQgdG8gdGhlIHZlY3Rvcml6ZWQgb3BlcmF0aW9uLgoKCmBgYHtyfQphbGdvcyA8LSBjKCJ2ZWN0b3JpemVkX2dlb21fbWVhbiIpCm5fdmFsdWVzIDwtIHNlcSgyLCA2LCBieSA9IDAuMSkKT19uIDwtIDEwXm5fdmFsdWVzLzEwXjQKT19uX3B5dGhvbl8xIDwtIE9fbipweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdJFRpbWVbM10KT19uX1JfMSA8LSBPX24qUltSJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdJFRpbWVbM10KcGxvdF9seSgpICU+JQogIGFkZF90cmFjZShkYXRhID0gUltSJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbG9vcF9nZW9tX21lYW4gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbG9vcF9nZW9tX21lYW4gUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKHggPSBuX3ZhbHVlcywgeSA9IE9fbl9SXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICBuYW1lID0gJ08obiknLCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIGRhc2ggPSAnZGFzaCcpKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiRXhlY3V0aW9uIFRpbWUiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChzKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCmBgYAoKCgojIyBNYXRyaXggb3BlcmF0aW9ucwojIyMgTWF0cml4IG11bHRpcGxpY2F0aW9uIGFuZCBpbnZlcnNpb24KCkZvciBlYWNoIHBhaXIgb2Ygcm93IGZyb20gJEEkIGFuZCBjb2x1bW4gZnJvbSAkQiQsICRuJCBtdWx0aXBsaWNhdGlvbnMgYXJlIHBlcmZvcm1lZC4gRm9yIGVhY2ggb2YgdGhlICRuJCBtdWx0aXBsaWNhdGlvbnMsIHRoZXJlIGlzIGFuIGFkZGl0aW9uLiBUaGlzIGdpdmVzIGNvbXB1dGF0aW9uYWwgY29tcGxleGl0eSAkXG1hdGhjYWx7T30obl4zKSQuIE5vdywgUHl0aG9uIGFuZCBSIGxpa2VseSBoYXZlIGEgbW9yZSBlZmZpY2llbnQgdmVyc2lvbiB0aHJvdWdoIHNvbWUgc21hcnQgYWxnb3JpdGhtLiBMaWtld2lzZSwgZmluZGluZyB0aGUgaW52ZXJzZSB0aHJvdWdoIEdhdXNzaWFuIGVsaW1pbmF0aW9uIGlzICRcbWF0aGNhbHtPfShuXjMpJC4gSG93ZXZlciwgdGhlIGltcGxlbWVudGF0aW9ucyBpbiBSIGFuZCBQeXRob24gc2VlbSB0byBzY2FsZSBsaW5lYXJseSBvciBldmVuIGJldHRlciB3aXRoICRuJC4gQW4gaW1wb3J0YW50IG5vdGUgaXMgdGhhdCBtZW1vcnkgYWxzbyBzZWVtcyB0byBpbmNyZWFzZSBsaW5lYXJseSB3aGljaCBtYXkgZXhwbGFpbiB3aHkgdGhlIHRpbWUgaXMgbXVjaCBiZXR0ZXIgdGhhbiB0aGUgdGhlb3JldGljYWwgY29tcGxleGl0eS4KCgpgYGB7ciBlY2hvPUZBTFNFfQphbGdvcyA8LSBjKCJtYXRyaXhfbXVsdGlwbGljYXRpb24iLCAibWF0cml4X2ludmVyc2lvbiIpCk9fbl9weXRob25fMSA8LSBPX24qcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSRUaW1lWzNdCk9fbl9SXzEgPC0gT19uKlJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSRUaW1lWzNdCk9fbl9weXRob25fMiA8LSBPX24qcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSRUaW1lWzNdCk9fbl9SXzIgPC0gT19uKlJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSRUaW1lWzNdCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ21hdHJpeF9tdWx0aXBsaWNhdGlvbiBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ2NpcmNsZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ21hdHJpeF9pbnZlcnNpb24gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdtYXRyaXhfbXVsdGlwbGljYXRpb24gUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbWF0cml4X2ludmVyc2lvbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGFkZF90cmFjZSh4ID0gbl92YWx1ZXMsIHkgPSBPX25fcHl0aG9uXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICBuYW1lID0gJ08obiknLCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIGRhc2ggPSAnZGFzaCcpKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiRXhlY3V0aW9uIFRpbWUiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChzKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbWF0cml4X211bHRpcGxpY2F0aW9uIFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnY2lyY2xlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gUltSJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdtYXRyaXhfaW52ZXJzaW9uIFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdkYXNoZG90JyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdtYXRyaXhfbXVsdGlwbGljYXRpb24gUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdtYXRyaXhfaW52ZXJzaW9uIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIk1lbW9yeSB1c2FnZSIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJsb2cobikiLCB0aWNrbW9kZSA9ICJhcnJheSIsIHRpY2t2YWxzID0gMDo2LCB0aWNrdGV4dCA9IGFzLmNoYXJhY3RlcigwOjYpKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIk1lbW9yeSAoTWlCKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCmBgYAoKCgpFaXRoZXIgJFxtYXRoY2Fse099KG4gZF4yKSQgb3IgJFxtYXRoY2Fse099KGReMykkLgoKCiMjIExpbmVhciByZWdyZXNzaW9uClJlY2FsbCB0aGUgT0xTICRcYmV0YSA9IChYXlQgWCleey0xfSBYXlQgeSQKCgoKYGBgcGxhaW50ZXh0CkZ1bmN0aW9uIGxpbmVhcl9yZWdyZXNzaW9uKFgsIHkpCiAgICBuIDwtIG51bWJlciBvZiByb3dzIGluIFgKICAgIHAgPC0gbnVtYmVyIG9mIGNvbHVtbnMgaW4gWAogICAgCiAgICAvLyBBdWdtZW50IFggd2l0aCBhIGNvbHVtbiAxIHRvIGluY2x1ZGUgYW4gaW50ZXJjZXB0CiAgICBYX2IgPC0gY29uY2F0ZW5hdGUoW29uZXMobiwgMSksIFhdLCBheGlzPTEpCiAgICAKICAgIC8vIENvbXB1dGUgdGhlIGNvZWZmaWNpZW50cwogICAgYmV0YV9oYXQgPC0gaW52ZXJzZShYX2IuVCBAIFhfYikgQCAoWF9iLlQgQCB5KSAKICAgIAogICAgUmV0dXJuIGJldGFfaGF0CkVuZCBGdW5jdGlvbgpgYGAKVGhlIG1hdHJpeCBhdWdtZW50YXRpb24gb3BlcmF0aW9uIGlzICRPKG4pJCBzaW5jZSB3ZSBhcmUgYXBwZW5kaW5nICRuJCByb3dzLiBUaGUgbWF0cml4IG11bHRpcGxpY2F0aW9uIGFuZCBpbnZlcnNpb24gYXJlIHRoZSBkb21pbmF0aW5nIHN0ZXBzIG9mIHRoaXMgYWxnb3JpdGhtLiBBcyBleHBsYWluZWQgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24gb24gbWF0cmljZXMsIHRoZSBtYXRyaXggbXVsdGlwbGljYXRpb24gWF9iLlQgQCBYX2Igc3RlcCBpcyAkTyhuIFx0aW1lcyAocCsxKV4yKSQgd2hpbGUgdGhlIG1hdHJpeCBpbnZlcnNpb24gaXMgJE8oKHArMSleMykkLCBhbHRob3VnaCB0aGVzZSBtYXRyaXggb3BlcmF0aW9ucyBhcmUgbGlrZWx5IGltcGxlbWVudGVkIG1vcmUgZWZmaWNpZW50bHkgaW4gUHl0aG9uIGFuZCBSLiBUaGUgbGFzdCBzdGVwIG9mIG11bHRpcGx5aW5nIHRoZSBtYXRyaXggaW52ZXJzZShYX2IuVCBAIFhfYikgd2l0aCB0aGUgdmVjdG9yIChYX2IuVCBAIHkpIGlzICRPKChwKzEpXjIpJC4gVGhlcmVmb3JlLCB0aGUgb3ZlcmFsbCBjb21wbGV4aXR5IGlzICRPKHBeMykkIG9yICRPKG4gXHRpbWVzIChwKzEpXjIpJCBkZXBlbmRpbmcgb24gd2hldGhlciAkcDw8biQuIEluIHRoaXMgY2FzZSwgc2luY2Ugd2Uga2VlcCAkcD0xMCQgYW5kIHdlIGluY3JlYXNlICRuJCB0byAkbj0xMF42JCwgdGhlIGRvbWluYXRpbmcgc3RlcCBpcyAkTyhuKSQuCgoKYGBge3IgZWNobz1GQUxTRX0KYWxnb3MgPC0gYygibGluZWFyX3JlZ3Jlc3Npb25fYmFzZSIsICJsaW5lYXJfcmVncmVzc2lvbl9wYWNrYWdlIikKT19uX3B5dGhvbl8xIDwtIE9fbipweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdJFRpbWVbM10KT19uX1JfMSA8LSBPX24qUltSJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdJFRpbWVbM10KT19uX3B5dGhvbl8yIDwtIE9fbipweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdJFRpbWVbM10KT19uX1JfMiA8LSBPX24qUltSJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdJFRpbWVbM10KcGxvdF9seSgpICU+JQogIGFkZF90cmFjZShkYXRhID0gUltSJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnbGluZWFyX3JlZ3Jlc3Npb25fc2NyYXRjaCBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ2NpcmNsZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xpbmVhcl9yZWdyZXNzaW9uX2Jhc2UgUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdsaW5lYXJfcmVncmVzc2lvbl9zY3JhdGNoIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnZG90JykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xpbmVhcl9yZWdyZXNzaW9uX3NrbGVhcm4gUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdkYXNoZG90JyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICAgIGFkZF90cmFjZSh4ID0gbl92YWx1ZXMsIHkgPSBPX25fUl8xLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywKICAgICAgICAgICAgbmFtZSA9ICdPKG4pJywgbGluZSA9IGxpc3QoY29sb3IgPSAnYmxhY2snLCBkYXNoID0gJ2Rhc2gnKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkV4ZWN1dGlvbiBUaW1lIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gImxvZyhuKSIsIHRpY2ttb2RlID0gImFycmF5IiwgdGlja3ZhbHMgPSAwOjYsIHRpY2t0ZXh0ID0gYXMuY2hhcmFjdGVyKDA6NikpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAocykiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpwbG90X2x5KCkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xpbmVhcl9yZWdyZXNzaW9uX3NjcmF0Y2ggUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xpbmVhcl9yZWdyZXNzaW9uX2Jhc2UgUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2xpbmVhcl9yZWdyZXNzaW9uX3NjcmF0Y2ggUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdsaW5lYXJfcmVncmVzc2lvbl9za2xlYXJuIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIk1lbW9yeSB1c2FnZSIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJsb2cobikiLCB0aWNrbW9kZSA9ICJhcnJheSIsIHRpY2t2YWxzID0gMDo2LCB0aWNrdGV4dCA9IGFzLmNoYXJhY3RlcigwOjYpKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIk1lbW9yeSAoTWlCKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCmBgYAoKCgojIyBCb290c3RyYXAKCkkgZXhwZWN0ZWQgY29tcHV0YXRpb25hbCBjb21wbGV4aXR5ICRcbWF0aGNhbHtPfShuIFxsb2cgKG4pKSQsIGJ1dCBQeXRob24gYmxvd3MgdXAuCgpgYGBwbGFpbnRleHQKRnVuY3Rpb24gYm9vdHN0cmFwKGRhdGEsIHN0YXRpc3RpYywgQiwgYWxwaGEpCiAgICBuIDwtIGxlbmd0aCBvZiBkYXRhCiAgICBpZHggPC0gZ2VuZXJhdGUgQiBzZXRzIG9mIGluZGljZXMsIGVhY2ggd2l0aCBuIHJhbmRvbSBpbnRlZ2VycyBiZXR3ZWVuIDAgYW5kIG4tMQogICAgc2FtcGxlcyA8LSBleHRyYWN0IGRhdGEgZWxlbWVudHMgYmFzZWQgb24gaWR4CiAgICBzdGF0IDwtIHNvcnQoc3RhdGlzdGljKHNhbXBsZXMpKQogICAgbG93ZXJfQ0kgPC0gY29tcHV0ZSAoMTAwKigxLWFscGhhKS8yKXRoIHNhbXBsZSBxdWFudGlsZQogICAgdXBwZXJfQ0kgPC0gY29tcHV0ZSAoMTAwKigxLSgxLWFscGhhKS8yKXRoIHNhbXBsZSBxdWFudGlsZQogICAgUmV0dXJuIGxvd2VyX0NJLCB1cHBlcl9DSQpFbmQgRnVuY3Rpb24KYGBgCgpUaGUgaWR4IHJlc2FtcGxpbmcgc3RlcCBpcyAkTyhuIFx0aW1lcyBCKSQgYW5kIGV4dHJhY3RpbmcgdGhlIHNhbXBsZXMgaXMgYWxzbyAkTyhuIFx0aW1lcyBCKSQuIEZvciBhIGxpbmVhciBzdGF0aXN0aWMgbGlrZSBhIHNhbXBsZSBtZWFuLCB0aGUgc3RhdGlzdGljIHN0ZXAgaXMgYWxzbyAkTyhuIFx0aW1lcyBCKSQuIFRoZSBzb3J0aW5nIHN0ZXAgZGVwZW5kcyBvbiB0aGUgYWxnb3JpdGhtIHVzZWQsIGJ1dCB0aGUgb25lIHVzZWQgaW4gUHl0aG9uIGlzIFRpbXNvcnQgd2hpY2ggaGFzICRPKEIgXGxvZyAoQikpJC4gQWZ0ZXIgdGhhdCwgY29tcHV0aW5nIHRoZSB0d28gc2FtcGxlIHF1YW50aWxlcyBvbiB0aGUgc29ydGVkIGRhdGEgaXMgJE8oMSkkLiBIb3dldmVyLCBhIHBvdGVudGlhbGx5IG1vcmUgZWZmaWNpZW50IHdheSBvZiBkb2luZyB0aGlzIHN0ZXAgaXMgdXNpbmcgc2FtcGxlIHF1YW50aWxlcyBzaW5jZSB3ZSBhcmUgb25seSBpbnRlcmVzdGVkIGluIHR3byBzYW1wbGUgcXVhbnRpbGVzIHdoaWNoIG1heSBhdm9pZCBzb3J0aW5nIHRoZSBlbnRpcmUgZGF0YXNldC4gVGhlcmVmb3JlLCBzaW5jZSB3ZSBpbmNyZWFzZSAkQiQgYW5kIGtlZXAgJG49MTBeMyQgZml4ZWQsIHRoZSBkb21pbmF0aW5nIHN0ZXAgaXMgdGhlIHJlc2FtcGxpbmcvZXh0cmFjdGluZy9zdGF0aXN0aWMgc3RlcCwgd2hpY2ggaGFzIGNvbXBsZXhpdHkgJE8obiBcdGltZXMgQikkLiAKCgoKYGBge3IgZWNobz1GQUxTRX0KYWxnb3MgPC0gYygiYm9vdHN0cmFwX2Jhc2UiLCAiYm9vdHN0cmFwX3BhY2thZ2UiKQpPX25fcHl0aG9uXzEgPC0gT19uKnB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0kVGltZVszXQpPX25fUl8xIDwtIE9fbipSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0kVGltZVszXQpPX25fcHl0aG9uXzIgPC0gT19uKnB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0kVGltZVszXQpPX25fUl8yIDwtIE9fbipSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0kVGltZVszXQpwbG90X2x5KCkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdib290c3RyYXBfc2NyYXRjaCBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ2NpcmNsZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2Jvb3RzdHJhcF9ib290IFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdkYXNoZG90JyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnYm9vdHN0cmFwX3NjcmF0Y2ggUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+VGltZSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnYm9vdHN0cmFwX3NjaXB5IFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKHggPSBuX3ZhbHVlcywgeSA9IE9fbl9SXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICBuYW1lID0gJ08obiknLCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIGRhc2ggPSAnZGFzaCcpKSAlPiUKICBhZGRfdHJhY2UoeCA9IG5fdmFsdWVzLCB5ID0gT19uX3B5dGhvbl8xLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywKICAgICAgICAgICAgbmFtZSA9ICdPKG4pJywgbGluZSA9IGxpc3QoY29sb3IgPSAnYmxhY2snLCBkYXNoID0gJ2Rhc2gnKSwgc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiRXhlY3V0aW9uIFRpbWUiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChzKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnYm9vdHN0cmFwX3NjcmF0Y2ggUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2Jvb3RzdHJhcF9ib290IFInLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJibHVlIiwgZGFzaCA9ICdkYXNoZG90JyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1sxXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdib290c3RyYXBfc2NyYXRjaCBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ2RvdCcpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ2Jvb3RzdHJhcF9zY2lweSBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGxheW91dCh0aXRsZSA9ICJNZW1vcnkgdXNhZ2UiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJNZW1vcnkgKE1pQikiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpgYGAKCgojIyBNYXJrb3YgY2hhaW4gTW9udGUgQ2FybG8KSSBleHBlY3QgdGhlIGNvbXB1dGF0aW9uYWwgY29tcGxleGl0eSB0byBiZSAkXG1hdGhjYWx7T30obikkLgoKYGBgcGxhaW50ZXh0CkZ1bmN0aW9uIG1ldHJvcG9saXNfaGFzdGluZ3MoWCwgeSwgQiwgYmV0YV8wLCBwcm9wb3NhbF9zZCwgc2lnbWEpCiAgICAvLyBBdWdtZW50IFggd2l0aCBhIGNvbHVtbiAxIHRvIGluY2x1ZGUgYW4gaW50ZXJjZXB0CiAgICBYX2IgPC0gY29uY2F0ZW5hdGUgY29sdW1uIG9mIG9uZXMgdG8gWAogICAgCiAgICAvLyBJbml0aWFsaXplIHBhcmFtZXRlcnMKICAgIGN1cnJlbnRfYmV0YSA8LSBiZXRhXzAKICAgIHNhbXBsZXMgPC0gY3VycmVudF9iZXRhCiAgICAKICAgIC8vIENvbXB1dGUgaW5pdGlhbCB2YWx1ZXMgZm9yIGxpa2VsaWhvb2QgYW5kIHByaW9yCiAgICBYYiA8LSBYX2IgZG90IGN1cnJlbnRfYmV0YQogICAgY3VycmVudF9saWtlbGlob29kIDwtIHN1bShsb2coTih5fFhiLHNpZ21hKSkKICAgIGN1cnJlbnRfcHJpb3IgPC0gc3VtKGxvZyhOKGN1cnJlbnRfYmV0YXxtdTAsc2lnbWEwKSkpCiAgICAKICAgIC8vIFNhbXBsaW5nCiAgICBGb3IgaSBmcm9tIDEgdG8gQgogICAgICAgIHByb3Bvc2VkX2JldGEgPC0gc2FtcGxlIE4oY3VycmVudF9iZXRhLHByb3Bvc2FsX3NkKQogICAgICAgIFhiX3Byb3Bvc2VkIDwtIFhfYiBkb3QgcHJvcG9zZWRfYmV0YQogICAgICAgIHByb3Bvc2VkX2xpa2VsaWhvb2QgPC0gc3VtKGxvZyhOKHl8WGJfcHJvcG9zZWQsc2lnbWEpKQogICAgICAgIHByb3Bvc2VkX3ByaW9yIDwtIHN1bShsb2coTihwcm9wb3NlZF9iZXRhfG11MCxzaWdtYTApKSkKICAgICAgICAKICAgICAgICAvLyBDb21wdXRlIGFjY2VwdGFuY2UgcHJvYmFiaWxpdHkKICAgICAgICBwX2FjY2VwdCA8LSBleHAocHJvcG9zZWRfbGlrZWxpaG9vZCArIHByb3Bvc2VkX3ByaW9yIC0gY3VycmVudF9saWtlbGlob29kIC0gY3VycmVudF9wcmlvcikKICAgICAgICAKICAgICAgICAvLyBBY2NlcHQvcmVqZWN0IG5ldyBiZXRhCiAgICAgICAgVSA8LSBzYW1wbGUgVW5pZigwLDEpCiAgICAgICAgSWYgVSA8IHBfYWNjZXB0CiAgICAgICAgICAgIGN1cnJlbnRfYmV0YSA8LSBwcm9wb3NlZF9iZXRhCiAgICAgICAgICAgIGN1cnJlbnRfbGlrZWxpaG9vZCA8LSBwcm9wb3NlZF9saWtlbGlob29kCiAgICAgICAgICAgIGN1cnJlbnRfcHJpb3IgPC0gcHJvcG9zZWRfcHJpb3IKICAgICAgICAKICAgICAgICBBcHBlbmQgY3VycmVudF9iZXRhIHRvIHNhbXBsZXMKICAgIAogICAgUmV0dXJuIHNhbXBsZXMKRW5kIEZ1bmN0aW9uCmBgYAoKQXVnbWVudGluZyB0aGUgbWF0cml4IGlzICRPKG4pJCwgdGhlIG1hdHJpeCBkb3QgcHJvZHVjdHMgZnJvbSBsaW5lYXIgcmVncmVzc2lvbiBpcyAkTyhucCkkLCBjb21wdXRpbmcgdGhlIGxvZy1saWtlbGlob29kIGlzICRPKG4pJCBhbmQgY29tcHV0aW5nIHRoZSBwcmlvciBpcyAkTyhwKSQuIFRoZXJlZm9yZSwgcnVubmluZyB0aGUgbG9vcCBmb3IgQiBpdGVyYXRpb25zIGhhcyBjb21wbGV4aXR5ICRPKG4gXHRpbWVzIHAgXHRpbWVzIEIpJC4KCgpgYGB7ciBlY2hvPUZBTFNFfQphbGdvcyA8LSBjKCJNZXRyb3BvbGlzX0hhc3RpbmdzIiwgIk1DTUNfc3RhbiIpCk9fbl9weXRob25fMSA8LSBPX24qcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSRUaW1lWzNdCk9fbl9SXzEgPC0gT19uKlJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSRUaW1lWzNdCk9fbl9weXRob25fMiA8LSBPX24qcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSRUaW1lWzNdCk9fbl9SXzIgPC0gT19uKlJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSRUaW1lWzNdCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ01ldHJvcG9saXNfSGFzdGluZ3MgUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdNQ01DX3N0YW4gUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ3NxdWFyZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdNZXRyb3BvbGlzX0hhc3RpbmdzIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnZG90JykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ01DTUNfc3RhbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGFkZF90cmFjZSh4ID0gbl92YWx1ZXMsIHkgPSBPX25fUl8xLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywKICAgICAgICAgICAgbmFtZSA9ICdPKG4pJywgbGluZSA9IGxpc3QoY29sb3IgPSAnYmxhY2snLCBkYXNoID0gJ2Rhc2gnKSkgJT4lCiAgYWRkX3RyYWNlKHggPSBuX3ZhbHVlcywgeSA9IE9fbl9weXRob25fMSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsCiAgICAgICAgICAgIG5hbWUgPSAnTyhuKScsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsYWNrJywgZGFzaCA9ICdkYXNoJyksIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lCiAgIyBhZGRfdHJhY2UoeCA9IG5fdmFsdWVzLCB5ID0gT19uX1JfMiwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsCiAgIyAgICAgICAgICAgbmFtZSA9ICdPKG4pJywgbGluZSA9IGxpc3QoY29sb3IgPSAnYmxhY2snLCBkYXNoID0gJ2Rhc2gnKSwgc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUKICAjIGFkZF90cmFjZSh4ID0gbl92YWx1ZXMsIHkgPSBPX25fcHl0aG9uXzIsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICMgICAgICAgICAgIG5hbWUgPSAnTyhuKScsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsYWNrJywgZGFzaCA9ICdkYXNoJyksIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkV4ZWN1dGlvbiBUaW1lIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gImxvZyhuKSIsIHRpY2ttb2RlID0gImFycmF5IiwgdGlja3ZhbHMgPSAwOjYsIHRpY2t0ZXh0ID0gYXMuY2hhcmFjdGVyKDA6NikpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAocykiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpwbG90X2x5KCkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ01ldHJvcG9saXNfSGFzdGluZ3MgUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ01DTUNfc3RhbiBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnTWV0cm9wb2xpc19IYXN0aW5ncyBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiwgc3ltYm9sID0gJ2RvdCcpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IHB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ01DTUNfc3RhbiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGxheW91dCh0aXRsZSA9ICJNZW1vcnkgdXNhZ2UiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJNZW1vcnkgKE1pQikiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpgYGAKCiMjIFN1cHBvcnQgdmVjdG9yIG1hY2hpbmUKCkkgd29uJ3Qgc2F5IG11Y2ggYWJvdXQgdGhpcyBiZWNhdXNlIEkgZG9uJ3Qga25vdyBtYWNoaW5lIGxlYXJuaW5nIGJ1dCBteSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBhbGdvcml0aG0gdXNpbmcgYSBzaW1wbGlmaWVkIGZvcm0gb2YgZ3JhZGllbnQgZGVzY2VudCBpcyBhcyBmb2xsb3dzLgoKYGBgcGxhaW50ZXh0CkZ1bmN0aW9uIHN2bShYLCB5LCBlcG9jaHMsIGxlYXJuaW5nX3JhdGUsIEMpCiAgICAvLyBJbml0aWFsaXplIHBhcmFtZXRlcnMKICAgIEluaXRpYWxpemUgd2VpZ2h0IHZlY3RvciB3IHRvIDAKICAgIEluaXRpYWxpemUgYmlhcyBiIHRvIDAKICAgIAogICAgRm9yIGVhY2ggZXBvY2ggZnJvbSAxIHRvIGVwb2NocwogICAgICAgIEZvciBlYWNoIHNhbXBsZSBpIGZyb20gMSB0byBsZW5ndGggb2YgeQogICAgICAgICAgICBDb21wdXRlIGRlY2lzaW9uX3ZhbHVlID0gWFtpXSBkb3QgKHcgKyBiKQogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ2hlY2sgaWYgZGF0YSBpcyBvbiB0aGUgY29ycmVjdCBzaWRlIG9mIHRoZSBtYXJnaW4KICAgICAgICAgICAgSWYgeVtpXSAqIGRlY2lzaW9uX3ZhbHVlIDwgMSB0aGVuCiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdyBhbmQgYiBmb3IgaW5jb3JyZWN0bHkgY2xhc3NpZmllZCBzYW1wbGVzCiAgICAgICAgICAgICAgICBVcGRhdGUgdyA9IHcgKyBsZWFybmluZ19yYXRlICogKHlbaV0gKiBYW2ldIC0gMiAqICgxL0MpICogdykKICAgICAgICAgICAgICAgIFVwZGF0ZSBiID0gYiArIGxlYXJuaW5nX3JhdGUgKiB5W2ldCiAgICAgICAgICAgIEVsc2UKICAgICAgICAgICAgICAgIC8vIEFwcGx5IG9ubHkgdGhlIHJlZ3VsYXJpemF0aW9uIHVwZGF0ZSBpZiBzYW1wbGUgaXMgY2xhc3NpZmllZCBjb3JyZWN0bHkKICAgICAgICAgICAgICAgIFVwZGF0ZSB3ID0gdyAtIGxlYXJuaW5nX3JhdGUgKiAoMiAqICgxL0MpICogdykKICAgICAgICAgICAgCiAgICBSZXR1cm4gdywgYgpFbmQgRnVuY3Rpb24KYGBgCgpUaGUgaW5pdGlhbGl6YXRpb25zIGFyZSAkTyhwKSQgYW5kICRPKDEpJCwgdGhlIG91dGVyIGxvb3AgcnVucyBmb3IgZXBvY2hzIGl0ZXJhdGlvbnMgYW5kIHRoZSBpbm5lciBsb29wIHJ1bnMgZm9yICRuJCBpbnRlcmF0aW9ucywgdGhlIHByb2R1Y3QgWFtpXSBkb3QgQyBpcyAkTyhwKSQsIHNvIHRoZSBvdmVyYWxsIGNvbXBsZXhpdHkgaXMgJE8oXHRleHR7ZXBvY2hzfSBcdGltZXMgbiBcdGltZXMgcCkkLgoKYGBge3IgZWNobz1GQUxTRX0KYWxnb3MgPC0gYygic3ZtX2Jhc2UiLCAic3ZtX3BhY2thZ2UiKQpPX25fcHl0aG9uXzEgPC0gT19uKnB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzFdLF0kVGltZVszXQpPX25fUl8xIDwtIE9fbipSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0kVGltZVszXQpPX25fcHl0aG9uXzIgPC0gT19uKnB5dGhvbltweXRob24kQWxnb3JpdGhtID09IGFsZ29zWzJdLF0kVGltZVszXQpPX25fUl8yIDwtIE9fbipSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0kVGltZVszXQpwbG90X2x5KCkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzFdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5UaW1lLCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdTVk1fc2NyYXRjaCBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJibHVlIiwgc3ltYm9sID0gJ2NpcmNsZScpKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ1NWTV9lMTA3MSBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ1NWTV9zY3JhdGNoIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnc29saWQnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnZG90JykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMl0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gflRpbWUsIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ1NWTV9za2xlYXJuIFB5dGhvbicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdzcXVhcmUnKSkgJT4lCiAgYWRkX3RyYWNlKHggPSBuX3ZhbHVlcywgeSA9IE9fbl9SXzEsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICBuYW1lID0gJ08obiknLCBsaW5lID0gbGlzdChjb2xvciA9ICdibGFjaycsIGRhc2ggPSAnZGFzaCcpKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiRXhlY3V0aW9uIFRpbWUiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChzKSIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gIkxlZ2VuZCIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4zLCB5ID0gLTAuMikpCnBsb3RfbHkoKSAlPiUKICBhZGRfdHJhY2UoZGF0YSA9IFJbUiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnU1ZNX3NjcmF0Y2ggUicsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBkYXNoID0gJ3NvbGlkJyksCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHN5bWJvbCA9ICdjaXJjbGUnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBSW1IkQWxnb3JpdGhtID09IGFsZ29zWzJdLF0sIHggPSB+bG9nKG4sIDEwKSwgeSA9IH5NZW1vcnksIAogICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBuYW1lID0gJ1NWTV9lMTA3MSBSJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGRhc2ggPSAnZGFzaGRvdCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGFkZF90cmFjZShkYXRhID0gcHl0aG9uW3B5dGhvbiRBbGdvcml0aG0gPT0gYWxnb3NbMV0sXSwgeCA9IH5sb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgCiAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIG5hbWUgPSAnU1ZNX3NjcmF0Y2ggUHl0aG9uJywKICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgZGFzaCA9ICdzb2xpZCcpLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJlZCIsIHN5bWJvbCA9ICdkb3QnKSkgJT4lCiAgYWRkX3RyYWNlKGRhdGEgPSBweXRob25bcHl0aG9uJEFsZ29yaXRobSA9PSBhbGdvc1syXSxdLCB4ID0gfmxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCAKICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbmFtZSA9ICdTVk1fc2tsZWFybiBQeXRob24nLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiLCBkYXNoID0gJ2Rhc2hkb3QnKSwKICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZWQiLCBzeW1ib2wgPSAnc3F1YXJlJykpICU+JQogIGxheW91dCh0aXRsZSA9ICJNZW1vcnkgdXNhZ2UiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAibG9nKG4pIiwgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IDA6NiwgdGlja3RleHQgPSBhcy5jaGFyYWN0ZXIoMDo2KSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJNZW1vcnkgKE1pQikiKSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9ICJMZWdlbmQiLCBvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuMywgeSA9IC0wLjIpKQpgYGAKCgo5IG1pbgoxMjZtaW4KCmFuZAoKIyBEaXNjdXNzaW9uCgojIyMjIExvb3BzCgrigJxGb3ItbG9vcHMgYXJlIG5vdCBpZGlvbWF0aWMgUiBjb2Rl4oCdIGlzIHNvbWV0aGluZyBJIGhhdmUgaGVhcmQgbWFueSB0aW1lcy4gSW4gdHJpdmlhbCBjYXNlcyBvciBmYXN0IHByb3RvdHlwaW5nLCBmb3ItbG9vcHMgYXJlIGZhbnRhc3RpYyB5ZXQgSSBoYXZlIGFsd2F5cyBjb252ZXJ0ZWQgdGhlbSBpbnRvIGJhc2U6OmFwcGx5IGZ1bmN0aW9ucywgb3IgcGJhcHBseTo6cGJhcHBseSBmb3IgcHJvZ3Jlc3MgYmFycyBvciBldmVuIHBhcmFsbGVsOjpwYXJBcHBseSBmb3IgcGFyYWxsZWwgY29tcHV0YXRpb24gYWZ0ZXJ3YXJkcy4KCgojIyMjIFNwZWVkIGRlcGVuZGluZyBvbiB0aGUgbWFjaGluZQoKIyMjIyBQcm9jZXNzb3IgdGltZSB2cy4gY2xvY2sgdGltZQpVbHRpbWF0ZWx5LCBJIGNhcmUgbW9yZSBhYm91dCBjbG9jayB0aW1lIGJ1dCBtYXliZSBmb3IgcHJvZHVjdGlvbiBjb2RlIGl0IGlzIHRvdGFsIHByb2Nlc3NpbmcgdGltZSBmcm9tIHBhcmVsbGVsIHNlcnZlcnMgdGhhdCBjb3VudHMuCgoKIyMjIyBXaGF0IGRvZXMgVGltZSB1c2FnZSByZWFsbHkgbWVhbiBhbmQgaG93IGNhbiB3ZSBtZWFzdXJlIGl0PwoKIyMjIyBFc3RpbWF0aW5nIHVuY2VydGFpbnR5IHdpdGhpbiBhbmQgYWNyb3NzIGRhdGFzZXRzIGFuZCBhY3Jvc3MgbWV0aG9kcwoKCiMjIyMgT3RoZXIgY29uc2lkZXJhdGlvbnMgdGhhbiBzcGVlZCBhbmQgVGltZQoKIyMjIyBNeSBleHBlcmllbmNlIHVzaW5nIGJvdGggUHl0aG9uIGFuZCBSCkl0IHdhcyBkaWZmaWN1bHQgdG8gc2ltdWxhdGUgdGhlIGRhdGEgYW5kIHN0b3JlIGluIGEgbWFubmVyIHRoYXQgY2FuIGJlIGVhc2lseSByZWFkIGluIGJvdGggUHl0aG9uIGFuZCBSLiBJZiBJIHdhcyBqdXN0IHVzaW5nIFIgSSB3b3VsZCB1c2UgYSAucmRzIGZpbGUgd2l0aCBhbiBhYnN1cmQgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBkYXRhIGluIG9uZSBvYmplY3QgZWFzaWx5IGltcG9ydGVkLCBidXQgdG8gYmUgcmVhZCBpbiBQeXRob24gSSBoYWQgdG8gc2F2ZSB0aGUgZGF0YSBpbiBzZXZlcmFsIC5jc3YgZmlsZXMgd2hpY2ggd2VyZSByZWFkIHdpdGggYW4gYXdrd2FyZCBzdHJ1Y3R1cmUgaW4gUHl0aG9uIGluY2x1ZGluZyBhbiBpbmZhbW91cyBlcnJvcnM9J2NvZXJjZScgbGluZS4gSSBkb24ndCByZWFsbHkgdW5kZXJzdGFuZCB3aGF0IGl0IGRvZXMgYnV0IGl0IHNvbHZlZCB0aGUgcHJvYmxlbSB0aGF0IG15IGZpbGUgaW5jbHVkZWQgYm90aCBzdHJpbmdzIGFuZCBudW1lcmljcywgdGhvdWdoIEkgb25seSBjYXJlIGFib3V0IGFuYWx5emluZyB0aGUgbnVtZXJpY3MuIFRoaXMgaXMgbXkgb3duIGZhdWx0IGJlY2F1c2UgSSBkb24ndCBrbm93IFB5dGhvbiB3ZWxsLCBidXQgUiBtYWtlcyBpdCAoZGFuZ2Vyb3VzbHkpIGVhc3kgdG8gdXNlIGRpZmZlcmVudCBvYmplY3RzIHdpdGhvdXQgdGhpbmtpbmcgYWJvdXQgc3RydWN0dXJlIHRvbyBtdWNoLiBGb3IgdGhlIHB1cnBvc2Ugb2YgdGhpcyBwcm9qZWN0LCBJIGRpZG4ndCByZWFsbHkgY2FyZSBtdWNoIGFib3V0IGltcG9ydGluZyB0aGUgZGF0YSBzbW9vdGhseSBhcyBsb25nIGFzIGl0IGdvdCBkb25lIHNpbmNlIEkgd2FzIGZvY3VzZWQgb24gbWFraW5nIHRoZSBhbGdvcml0aG1zIGNvbXBhcmFibGUuIEFuIGludGVyZXN0aW5nIGFzcGVjdCB0aGF0IEkgZGlkbid0IHRlc3Qgd2FzIHRoZSBzcGVlZCBvZiByZWFkaW5nIGRhdGEsIHdoaWNoIEkgY2xlYXJseSBkb24ndCBrbm93IGVub3VnaCBhYm91dCB0byB0ZXN0IGZhaXJseSwgYnV0IGl0IGNhbiBiZSBhIG1ham9yIGNvbnNpZGVyYXRpb24gZm9yIGxhcmdlIGRhdGFzZXRzIHdoaWNoIGNhbiBuZWVkIGNsdXN0ZXJzIG9mIENQVXMgdG8gbG9hZC4KCgojIyMjIE15IGV4cGVyaWVuY2UgdXNpbmcgaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiBhbmQgYSB3ZWJzaXRlClBsb3R0aW5nIGlzIG11Y2ggZWFzaWVyIGFuZCBiZXR0ZXIgc3VwcG9ydGVkIGluIGdncGxvdCwgYnV0IEkgdXNlZCBwbG90bHkgdG8gbWFrZSB0aGVzZSBpbnRlcmFjdGl2ZSBwbG90cy4KSSBkb24ndCByZWFsbHkgbGlrZSB0aGVtIGZvciBjb252ZXlpbmcgaW5mb3JtYXRpb24sIGFzIEkgdGhpbmsgdGhleSB1bHRpbWF0ZWx5IGRpc3RyYWN0IHRoZSByZWFkZXIgZnJvbSB0aGUgaW5mb3JtYXRpb24sIGJ1dCBpdCBhdHRyYWN0cyBhdHRlbnRpb24gYW5kIGlzIGludGVyZXN0aW5nIGZvciBhIGJsb2cgcG9zdCBmb3JtYXQgbGlrZSB0aGlzLiBJIGNvdWxkIG5vdCBpbWFnaW5lIHVzaW5nIHRoZW0gaW4gYSBwYXBlci4KCgojIyMjIFVzYWdlIGluIGluZHVzdHJ5IGFuZCBhY2FkZW1pYQoKIyMjIyBQcm9iYWJpbGlzdGljIHByb2dyYW1pbmcgYW5kIGJheWVzaWFuIHN0YXRpc3RjcwoKQ29tcGFyaW5nIE1DTUMgc2FtcGxlcnM6Cmh0dHBzOi8vc3RhdG1vZGVsaW5nLnN0YXQuY29sdW1iaWEuZWR1LzIwMjQvMDQvMjcvZXZhbHVhdGluZy1tY21jLXNhbXBsZXJzLwoKCiMgUmVmZXJlbmNlcwoKCgpgYGB7ciBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQpsaWJyYXJ5KHBsb3RseSkKUiA8LSByZWFkLmNzdigiL1VzZXJzL2FuY2F2YW5jaXVwb3Blc2N1L0Rlc2t0b3AvQ2xhc3Nlcy9DUyAzMi9GaW5hbCBwcm9qZWN0L1Jlc3VsdHMvUmVzdWx0c19SLmNzdiIpCnB5dGhvbiA8LSByZWFkLmNzdigiL1VzZXJzL2FuY2F2YW5jaXVwb3Blc2N1L0Rlc2t0b3AvQ2xhc3Nlcy9DUyAzMi9GaW5hbCBwcm9qZWN0L1Jlc3VsdHMvUmVzdWx0c19weXRob24uY3N2IikKbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoUiwgcHl0aG9uLCBieT1jKCJBbGdvcml0aG0iLCAibiIpLCBzdWZmaXhlcyA9IGMoIlIiLCAicHl0aG9uIikpCmFsZ29yaXRobV9uYW1lcyA8LSBjKCdsb29wX3N1bScsJ2xvb3BfZ2VvbV9tZWFuJywgJ3ZlY3Rvcml6ZWRfZ2VvbV9tZWFuJywgJ21hdHJpeF9tdWx0aXBsaWNhdGlvbicsIAogICAgICAgICAgICAgICAgICdtYXRyaXhfaW52ZXJzaW9uJywgJ2xpbmVhcl9yZWdyZXNzaW9uX3BhY2thZ2UnLCAnbGluZWFyX3JlZ3Jlc3Npb25fYmFzZScsIAogICAgICAgICAgICAgICAgICdib290c3RyYXBfcGFja2FnZScsICdib290c3RyYXBfYmFzZScsICdzdm1fcGFja2FnZScsICdzdm1fYmFzZScsIAogICAgICAgICAgICAgICAgICdNZXRyb3BvbGlzX0hhc3RpbmdzJywgJ01DTUNfc3RhbicpCgojIENyZWF0ZSBwbG90cyBmb3IgZXhlY3V0aW9uIHRpbWUKcGxvdF90aW1lX2xpc3QgPC0gbGlzdCgpCmZvciAoYWxnIGluIGFsZ29yaXRobV9uYW1lcykgewogIGFsZ19SIDwtIHN1YnNldChSLCBBbGdvcml0aG0gPT0gYWxnKQogIGFsZ19QeXRob24gPC0gc3Vic2V0KHB5dGhvbiwgQWxnb3JpdGhtID09IGFsZykKCiAgcCA8LSBwbG90X2x5KCkgJT4lCiAgICBhZGRfdHJhY2UoZGF0YSA9IGFsZ19SLCB4ID0gfiBsb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywKICAgICAgICAgICAgICBuYW1lID0gJ1InLCBsaW5lID0gbGlzdChjb2xvciA9ICdibHVlJykpICU+JQogICAgYWRkX3RyYWNlKGRhdGEgPSBhbGdfUHl0aG9uLCB4ID0gfiBsb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywKICAgICAgICAgICAgICBuYW1lID0gJ1B5dGhvbicsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ29yYW5nZScpKSAlPiUKICAgIGxheW91dCh0aXRsZSA9IHBhc3RlKCJFeGVjdXRpb24gdGltZSBmb3IiLCBhbGcpLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJsb2cobikiLCB0aWNrbW9kZSA9ICJhcnJheSIsIHRpY2t2YWxzID0gMDo2LCB0aWNrdGV4dCA9IGFzLmNoYXJhY3RlcigwOjYpKSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAocykiKSwKICAgICAgICAgICBsZWdlbmQgPSBsaXN0KHggPSAwLjEsIHkgPSAwLjkpKQoKICBwbG90X3RpbWVfbGlzdFtbYWxnXV0gPC0gcAp9CgojIENyZWF0ZSBwbG90cyBmb3IgVGltZSB1c2FnZQpwbG90X1RpbWVfbGlzdCA8LSBsaXN0KCkKZm9yIChhbGcgaW4gYWxnb3JpdGhtX25hbWVzKSB7CiAgYWxnX1IgPC0gc3Vic2V0KFIsIEFsZ29yaXRobSA9PSBhbGcpCiAgYWxnX1B5dGhvbiA8LSBzdWJzZXQocHl0aG9uLCBBbGdvcml0aG0gPT0gYWxnKQoKICBwIDwtIHBsb3RfbHkoKSAlPiUKICAgIGFkZF90cmFjZShkYXRhID0gYWxnX1IsIHggPSB+IGxvZyhuLCAxMCksIHkgPSB+TWVtb3J5LCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLAogICAgICAgICAgICAgIG5hbWUgPSAnUicsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsdWUnLCBkYXNoID0gJ3NvbGlkJykpICU+JQogICAgYWRkX3RyYWNlKGRhdGEgPSBhbGdfUHl0aG9uLCB4ID0gfiBsb2cobiwgMTApLCB5ID0gfk1lbW9yeSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywKICAgICAgICAgICAgICBuYW1lID0gJ1B5dGhvbicsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ29yYW5nZScsIGRhc2ggPSAnZGFzaGRvdCcpKSAlPiUKICAgIGxheW91dCh0aXRsZSA9IHBhc3RlKCJUaW1lIHVzYWdlIGZvciIsIGFsZyksCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gImxvZyhuKSIsIHRpY2ttb2RlID0gImFycmF5IiwgdGlja3ZhbHMgPSAwOjYsIHRpY2t0ZXh0ID0gYXMuY2hhcmFjdGVyKDA6NikpLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChNaUIpIiksCiAgICAgICAgICAgbGVnZW5kID0gbGlzdCh4ID0gMC4xLCB5ID0gMC45KSkKCiAgcGxvdF9UaW1lX2xpc3RbW2FsZ11dIDwtIHAKfQoKZm9yICh2YXJpYWJsZSBpbiB2ZWN0b3IpIHsKICAKfQojIFByaW50IHBsb3RzIGZvciBsb29wX3N1bQpmb3IgKGFsZ28gaW4gYWxnb3JpdGhtX25hbWVzKSB7CiAgcHJpbnQocGxvdF90aW1lX2xpc3RbW2FsZ29dXSkKfQpgYGAKCgo=